﻿using System.Data;
using System.Net;
using System.Reflection;
using System.Runtime.InteropServices;

using BodaNetCommunications.Cores;
using BodaNetCommunications.McComs.McComsUtil;
using BodaNetCommunications.Utilities.ComTypes;
using BodaNetCommunications.Utilities.Results;

namespace BodaNetCommunications.McComs
{
    /// <summary>
    /// 1. Mc协议是小端处理数据
    /// 2. 适用于三菱和基恩士的Mc协议数据采集
    /// </summary>
    public class McQnA3E : ICommDevice
    {
        public McPLCType McPLCType { get; private set; }

        public ConnectionOptions Options { get; private set; }

        private ICommUnit _commUnit;

        public bool IsConnected => _commUnit != null && _commUnit.IsConnected;

        public McQnA3E()
        {

        }

        // 握手报文
        public BodaResult Connect(ConnectionOptions connectionOptions)
        {
            BodaResult bodaResult = new BodaResult();
            McPLCType = connectionOptions.PlcType;
            Options = connectionOptions;
            if (string.IsNullOrEmpty(Options.Ip) || false == IPAddress.TryParse(Options.Ip, out _))
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"Ip[{Options.Ip}]为空或者格式不正确";
                return bodaResult;
            }

            if (Options.Port < 0 || Options.Port > 65535)
            {
                bodaResult.IsSuccess = false;
                bodaResult.Message = $"Port[{Options.Port}]不正确";
                return bodaResult;
            }

            if (IsConnected)
            {

                bodaResult.IsSuccess = true;
                bodaResult.Message = $"Mc【{Options.Ip}:{Options.Port}】的连接已经在线，不需要重复连接";
                return bodaResult;
            }


            _commUnit = new CommUnitMc(Options.Ip.Trim(), Options.Port);

            return _commUnit.Open(Options.ConnectTimeout);
        }

        public void Disconnect()
        {
            _commUnit.Close();
        }

        #region 读取

        /// <summary>
        /// 读取数据的字节数组
        /// </summary>
        /// <param name="area"></param>
        /// <param name="startAddr"></param>
        /// <param name="length"></param>
        /// <returns></returns>
        public BodaResult<byte[]> ReadBytes(string startAddr, ushort length)
        {
            BodaResult<byte[]> result = new BodaResult<byte[]>();

            try
            {
                byte subCmd = 0x00;

                List<byte> startBytes = new List<byte>();


                var (area, address) = McHelper.McTranferAddress(startAddr);

                if (!int.TryParse(address, out int addr))
                {
                    result.IsSuccess = false;
                    result.Message = $"【{nameof(McQnA3E)}】软元件地址不支持！";
                    return result;
                }
                startBytes.Add((byte)(addr % 256));
                startBytes.Add((byte)(addr / 256 % 256));
                startBytes.Add((byte)(addr / 256 / 256 % 256));

                List<byte> bytes = new List<byte>
                {
                    0x50,0x00,
                    0x00,
                    0xFF,
                    0xFF,0x03,
                    0x00,

                    0x0C,0x00,  // 剩余字节长度
                    0x0A,0x00,

                    0x01,0x04,// 成批读出
                    subCmd,0x00,// 位操作
                };
                // 起始地址
                bytes.AddRange(startBytes);
                // 区域代码
                bytes.Add((byte)area);
                // 读取长度
                bytes.AddRange(BitConverter.GetBytes(length));


                // 发送并接收响应报文
                BodaResult<byte> dataResult = _commUnit.SendAndReceive(bytes);
                if (false == dataResult.IsSuccess)
                {
                    result.IsSuccess = false;
                    result.Message = $"【{nameof(McQnA3E)}】" + dataResult.Message;
                    return result;
                }

                // 开始做异常判断
                List<byte> stateBytes = dataResult.Datas.GetRange(9, 2);
                stateBytes.Reverse();
                string errorCode = string.Join("", stateBytes.Select(s => s.ToString("X2")));
                if (errorCode != "0000")
                {
                    result.IsSuccess = false;
                    result.IsSuccess = false;

                    if (Errors.ResponseError.ContainsKey(errorCode))
                        result.Message = $"【{nameof(McQnA3E)}】" + Errors.ResponseError[errorCode];
                    else
                        result.Message = $"【{nameof(McQnA3E)}】" + "未知异常";

                    return result;
                }

                // 数据解析
                List<byte> dataBytes = dataResult.Datas.GetRange(11, dataResult.Datas.Count - 11);

                result.Content = dataBytes.ToArray();
                result.IsSuccess = true;
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.IsSuccess = false;
                result.Message = $"【{nameof(McQnA3E)}】Error: " + ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 成批读取数据，按照地址读取连续的数据
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="area">位/字</param>
        /// <param name="startAddr">地址编号</param>
        /// <param name="count">
        /// 读取个数
        /// 1. 指的是多少个寄存器还是多少个数据？这里指取多少个数据
        /// 2. 比如：float需要2个寄存器， 如果按照读取寄存器则会出错
        /// 3. D0 1个点对应1个地址
        /// 4. X0 1个点对应1个地址
        /// </param>
        /// <returns></returns>
        public BodaResult<T> BatchRead<T>(McAddressArea area, string startAddr, ushort count)
        {
            BodaResult<T> result = new BodaResult<T>();
            try
            {
                byte subCmd = 0x01;
                int typeLen = 1;

                // 如果不是bool值，则子命令修改位0x00，按照字去读取数据
                if (typeof(T) != typeof(bool))
                {
                    subCmd = 0x00;
                    // 当前类型下，每个数据需要多少个寄存器
                    // 比如float为4个字节 -> 需要2个地址，每个地址2个字，共4个字节
                    typeLen = Marshal.SizeOf<T>() / 2;
                }

                List<byte> startBytes = new List<byte>();
                if (area == McAddressArea.X || area == McAddressArea.Y)
                {
                    // 直接将字符串转换为16进制，一个字节
                    //Convert.ToByte("10",16)  =>   0x10
                    //Convert.ToByte("0A",16)  =>   0x0A

                    // 将 "10A" 不足6位，补0， 得到 "00010A"
                    string str = startAddr.PadLeft(6, '0');

                    #region FromHexString

                    // 为什么使用for循环而不用FromHexString？
                    // 原因在于FromHexString不支持Framework框架
                    //// 将"00010A" 转换为 0x00,0x01,0x0A
                    //var bytesAddr = Convert.FromHexString(str);
                    //startBytes.AddRange(bytesAddr);
                    //// 将0x00,0x01,0x0A 倒叙为 0x0A ,0x01 ,0x00
                    //startBytes.Reverse();

                    #endregion FromHexString

                    // 共6个字符，每次循环后，间隔为2，共循环3次
                    for (int i = 0; i < 6; i += 2)
                    {
                        string a = str[i].ToString() + str[i + 1].ToString();
                        startBytes.Add(Convert.ToByte(a, 16));
                    }
                    startBytes.Reverse();
                }
                else
                {
                    if (!int.TryParse(startAddr, out int addr))
                    {
                        result.IsSuccess = false;
                        result.IsSuccess = false;
                        result.Message = "软元件地址不支持！";
                        return result;
                    }
                    startBytes.Add((byte)(addr % 256));
                    startBytes.Add((byte)(addr / 256 % 256));
                    startBytes.Add((byte)(addr / 256 / 256 % 256));
                }

                List<byte> bytes = new List<byte>
                {
                    0x50,0x00,
                    0x00,
                    0xFF,
                    0xFF,0x03,
                    0x00,

                    0x0C,0x00,  // 剩余字节长度
                    0x0A,0x00,

                    0x01,0x04,// 成批读出
                    subCmd,0x00,// 位操作
                };
                // 起始地址
                bytes.AddRange(startBytes);
                // 区域代码
                bytes.Add((byte)area);
                // 读取长度
                bytes.AddRange(BitConverter.GetBytes(typeLen * count));

                // 发送并接收响应报文
                BodaResult<byte> dataResult = _commUnit.SendAndReceive(bytes);
                if (false == dataResult.IsSuccess)
                {
                    result.IsSuccess = false;
                    result.IsSuccess = false;
                    result.Message = dataResult.Message;
                    return result;
                }

                // 开始做异常判断
                List<byte> stateBytes = dataResult.Datas.GetRange(9, 2);
                stateBytes.Reverse();
                string errorCode = string.Join("", stateBytes.Select(s => s.ToString("X2")));
                if (errorCode != "0000")
                {
                    result.IsSuccess = false;
                    result.IsSuccess = false;

                    if (Errors.ResponseError.ContainsKey(errorCode))
                        result.Message = Errors.ResponseError[errorCode];
                    else
                        result.Message = "未知异常";

                    return result;
                }

                // 数据解析
                List<byte> dataBytes = dataResult.Datas.GetRange(11, dataResult.Datas.Count - 11);

                result.DataBytes.AddRange(stateBytes);
                // 两部分：按字处理、按位处理
                if (typeof(T) == typeof(bool))
                {
                    // 每个字节有两个状态
                    // 高4位一个状态   0001:True;0000:False
                    // 低4位状态同上
                    int index = 0;
                    for (int i = 0; i < count; i++)
                    {
                        dynamic bValue = false;
                        // 偶数位的数据位于高四位，奇数位的数据位于第四位
                        if (i % 2 == 0)
                        {
                            // 与1相与运算，得出bool值
                            bValue = (dataBytes[index] & (1 << 4)) != 0;
                        }
                        else
                        {
                            bValue = (dataBytes[index] & 1) != 0;
                            index++;
                        }
                        result.Datas.Add(bValue);
                    }
                }
                else
                {
                    // 当前数据类型所需的字节数
                    int len = typeLen * 2;
                    for (int i = 0; i < dataBytes.Count; i += len)
                    {
                        // 获取每个数据的基础字节
                        List<byte> vBytes = dataBytes.GetRange(i, len);
                        if (vBytes == null || vBytes.Count == 0)
                        {
                            result.IsSuccess = false;
                            result.Message = "数据字节为空";
                            return result;
                        }
                        //vBytes.Reverse();   // 不需要做字节序的调整，报文中的字节序与BitConverter的字节一致

                        // 从字节到数据的转换（使用反射，获取对应类型的转换方法）
                        Type tBitConverter = typeof(BitConverter);
                        // 比如方法： ToUInt32(byte[] value, int startIndex)
                        MethodInfo? method = tBitConverter.GetMethods(BindingFlags.Public | BindingFlags.Static)
                                                        .FirstOrDefault(mi => mi.ReturnType == typeof(T) &&
                                                        // 方法参数的数量等于2的方法才能用，第一个是字节数组，第二个是数组开始索引
                                                        mi.GetParameters().Length == 2) as MethodInfo;
                        if (method == null)
                        {
                            result.IsSuccess = false;
                            result.Message = "未找到匹配的数据类型转换方法";
                            return result;
                        }

                        result.Datas.Add((T)(method.Invoke(tBitConverter, new object[] { vBytes!.ToArray(), 0 }) ?? throw new Exception("字节到数据的转换的方式Invoke失败")));
                    }
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }

            return result;
        }

        /// <summary>
        /// 根据地址解析服务
        /// </summary>
        /// <typeparam name="T">返回的数据类型</typeparam>
        /// <param name="address">地址</param>
        /// <param name="count">数据数量</param>
        /// <returns></returns>
        public BodaResult<T> BatchRead<T>(string address, ushort count)
        {
            BodaResult<T> result = new BodaResult<T>();
            try
            {
                var (a, s) = McHelper.McTranferAddress(address);
                result = this.BatchRead<T>(a, s, count);
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 随机读出报文
        /// 1. D0 1个点对应1个地址
        /// 2. X0 1个点对应16个地址 16位寄存器: 0-F 放在连个字节中返回  8位寄存器: 0-7 10-17 放在两个字节中返回
        /// 3. M0 1个点对应16个地址 0-16 放在连个字节中返回
        /// </summary>
        /// <param name="parameters">参数列表</param>
        /// <returns></returns>
        public BodaResult RandomRead(List<McDataParameter> parameters)
        {
            BodaResult result = new BodaResult();
            try
            {
                List<byte> bytes = new List<byte>
                {
                    0x50,0x00,
                    0x00,
                    0xFF,
                    0xFF,0x03,
                    0x00,

                    0x0C,0x00,  // 剩余字节长度
                    0x0A,0x00,

                    0x03,0x04,// 成批读出
                    0x00,0x00,// 位操作
                };
                // 排序的目的是为了后面做报文拼接的时候保证双字的请求地址在后面
                // 这里正序是先False还是先True？
                List<McDataParameter> sortList = parameters.OrderBy(p => p.IsSecond).ToList();
                // 拼接字处理点数，并转换成字节数
                bytes.Add(BitConverter.GetBytes(sortList.Count(s => !s.IsSecond))[0]);
                // 拼接双字处理点数
                bytes.Add(BitConverter.GetBytes(sortList.Count(s => s.IsSecond))[0]);

                foreach (var p in sortList)
                {
                    List<byte> startBytes = new List<byte>();
                    if (p.Area == McAddressArea.X || p.Area == McAddressArea.Y)
                    {
                        string str = p.Start.PadLeft(6, '0');
                        for (int i = 0; i < 6; i += 2)
                        {
                            string a = str[i].ToString() + str[i + 1].ToString();
                            startBytes.Add(Convert.ToByte(a, 16));
                        }
                        startBytes.Reverse();
                    }
                    else
                    {
                        if (!int.TryParse(p.Start, out int addr))
                        {
                            result.Message = "软元件地址不支持！";
                            result.IsSuccess = false;
                            return result;
                        }
                        startBytes.Add((byte)(addr % 256));
                        startBytes.Add((byte)(addr / 256 % 256));
                        startBytes.Add((byte)(addr / 256 / 256 % 256));
                    }

                    bytes.AddRange(startBytes);// 当前一个地址的起始位置
                    bytes.Add((byte)p.Area);
                }
                // 处理报文中的字节数量
                ushort bytesCount = (ushort)(bytes.Count - 9);
                bytes[7] = BitConverter.GetBytes(bytesCount)[0];
                bytes[8] = BitConverter.GetBytes(bytesCount)[1];

                // 发送并接收响应报文 --  进行解析
                BodaResult<byte> dataResult = _commUnit.SendAndReceive(bytes);
                if (!dataResult.IsSuccess)
                {
                    result.Message = dataResult.Message;
                    result.IsSuccess = false;
                    return result;
                }

                // 开始做异常判断
                List<byte> stateBytes = dataResult.Datas.GetRange(9, 2);
                stateBytes.Reverse();
                string errorCode = string.Join("", stateBytes.Select(s => s.ToString("X2")));
                if (errorCode != "0000")
                {
                    if (Errors.ResponseError.ContainsKey(errorCode))
                        result.Message = Errors.ResponseError[errorCode];
                    else
                        result.Message = "未知异常";

                    result.IsSuccess = false;
                    return result;
                }
                // 数据解析
                List<byte> dataBytes = dataResult.Datas.GetRange(11, dataResult.Datas.Count - 11);

                int index = 0;
                foreach (var item in sortList)
                {
                    int typeLen = Marshal.SizeOf(item.DataType);

                    // 获取每个数据的基础字节
                    List<byte> vBytes = dataBytes.GetRange(index, typeLen);
                    //vBytes.Reverse();   // 不需要做字节序的调整，报文中的字节序与BitConverter的字节一致

                    // 从字节到数据的转换（使用反射，获取对应类型的转换方法）
                    Type tBitConverter = typeof(BitConverter);
                    MethodInfo method = tBitConverter.GetMethods(BindingFlags.Public | BindingFlags.Static)
                        .FirstOrDefault(
                            mi => mi.ReturnType == item.DataType &&
                            mi.GetParameters().Length == 2) as MethodInfo
                            ?? throw new Exception($"未获取到[{item.DataType}]对应类型的转换方法");
                    if (method == null)
                    {
                        result.Message = "未找到匹配的数据类型转换方法";
                        result.IsSuccess = false;
                        return result;
                    }

                    item.Datas.Add(method.Invoke(tBitConverter, new object[] { vBytes.ToArray(), 0 })
                            ?? throw new Exception($"数据类型[{item.DataType}]对应类型的转换方法Invoke失败"));

                    index += typeLen;
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }

            return result;
        }

        /// <summary>
        /// 多块成批读取:
        ///     TODO: 扩展读取位的功能，通过读取字或者字节，取出对应的位
        /// 1. D0 1个点对应1个地址
        /// 2. X0 1个点对应16个地址 16位寄存器: 0-F 放在连个字节中返回  8位寄存器: 0-7 10-17 放在两个字节中返回
        /// 3. M0 1个点对应16个地址 0-16 放在连个字节中返回
        /// </summary>
        /// <param name="parameters"></param>
        /// <returns></returns>
        public BodaResult MultiRead(List<McDataParameter> parameters)
        {
            BodaResult result = new BodaResult();
            try
            {
                ushort num = (ushort)(parameters.Count * 6 + 8);
                List<byte> bytes = new List<byte>
                {
                    0x50,0x00,
                    0x00,
                    0xFF,
                    0xFF,0x03,
                    0x00
                };
                // 后续字节数
                bytes.AddRange(BitConverter.GetBytes(num));
                // PLC处理超时时间
                bytes.AddRange(new byte[] { 0x0A, 0x00 });
                // 主操作码
                bytes.AddRange(new byte[] { 0x06, 0x04 });
                // 子操作码
                bytes.AddRange(new byte[] { 0x00, 0x00 });

                // 计算两种类型的处理块数
                bytes.Add(BitConverter.GetBytes(parameters.Count(s => !s.IsSecond))[0]);// 拼接字处理点数
                bytes.Add(BitConverter.GetBytes(parameters.Count(s => s.IsSecond))[0]);// 拼接双字处理点数 

                // 按照参数类型进行排序，字地址在前，位地址在后
                List<McDataParameter> sortList = parameters.OrderBy(p => p.IsSecond).ToList();

                foreach (var item in sortList)
                {
                    List<byte> startBytes = new List<byte>();
                    if (item.Area == McAddressArea.X || item.Area == McAddressArea.Y)
                    {
                        string str = item.Start.PadLeft(6, '0');
                        for (int i = 0; i < 6; i += 2)
                        {
                            string a = str[i].ToString() + str[i + 1].ToString();
                            startBytes.Add(Convert.ToByte(a, 16));
                        }
                        startBytes.Reverse();
                    }
                    else
                    {
                        if (!int.TryParse(item.Start, out int addr))
                        {
                            throw new Exception("软元件地址不支持！");
                        }
                        startBytes.Add((byte)(addr % 256));
                        startBytes.Add((byte)(addr / 256 % 256));
                        startBytes.Add((byte)(addr / 256 / 256 % 256));
                    }

                    bytes.AddRange(startBytes);// 当前一个地址的起始位置
                    bytes.Add((byte)item.Area);// 添加存储区编号

                    // Count  ：数据个数，不是地址个数   不是点数，与类型相关
                    // 例：ushort  1       float    1
                    //      D   1                   2    2个地址
                    //      X   1                   2    32个地址
                    // X0  开始请求一个点：随机、多块成批     16个位    X0-XF    X0-X7  X10-X17（16进制，或者8进制）
                    //                    成批：一个点就是一个位
                    // M0  开始请求一个点：随机、多块成批     M0-M16（10进制）
                    ushort len = (ushort)(Marshal.SizeOf(item.DataType) / 2 * item.Count);
                    bytes.AddRange(BitConverter.GetBytes(len));// 区分D  字区   X  位区   不需要
                }

                // 发送并接收响应报文 --  进行解析
                BodaResult<byte> dataResult = _commUnit.SendAndReceive(bytes);
                if (!dataResult.IsSuccess)
                {
                    result.IsSuccess = false;
                    result.Message = dataResult.Message;
                }

                // 开始做异常判断 
                List<byte> stateBytes = dataResult.Datas.GetRange(9, 2);
                stateBytes.Reverse();
                string errorCode = string.Join("", stateBytes.Select(s => s.ToString("X2")));
                if (errorCode != "0000")
                {
                    if (Errors.ResponseError.ContainsKey(errorCode))
                    {
                        result.IsSuccess = false;
                        result.Message = Errors.ResponseError[errorCode];
                    }
                    else
                    {
                        result.IsSuccess = false;
                        result.Message = "未知异常";
                    }
                }
                // 数据解析
                List<byte> dataBytes = dataResult.Datas.GetRange(11, dataResult.Datas.Count - 11);

                int index = 0;
                foreach (var item in sortList)
                {
                    for (int i = 0; i < item.Count; i++)
                    {
                        int len = Marshal.SizeOf(item.DataType);
                        List<byte> vBytes = dataBytes.GetRange(index, len);

                        // 数据转换  byte[]->type
                        Type tBitConverter = typeof(BitConverter);
                        MethodInfo method = tBitConverter.GetMethods(BindingFlags.Public | BindingFlags.Static)
                            .FirstOrDefault(
                                mi => mi.ReturnType == item.DataType &&
                                mi.GetParameters().Length == 2
                                ) as MethodInfo
                            ?? throw new Exception($"未获取到[{item.DataType}]对应类型的转换方法");
                        if (method == null)
                        {
                            result.IsSuccess = false;
                            result.Message = "未找到匹配的数据类型转换方法";
                        }

                        item.Datas.Add(method?.Invoke(tBitConverter, new object[] { vBytes.ToArray(), 0 })
                                ?? throw new Exception($"数据类型[{item.DataType}]对应类型的转换方法Invoke失败"));

                        index += len;
                    }
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }

            return result;
        }
        #endregion

        #region 写入

        public BodaResult Write(string startAddr, byte[] data)
        {
            var (area, address) = McHelper.McTranferAddress(startAddr);
            var shortVal = BitConverter.ToInt16(data);
            var res = BatchWrite(area, address, new List<short>() { shortVal });
            return res;
        }

        public BodaResult BatchWrite<T>(McAddressArea area, string startAddr, List<T> values)
        {
            BodaResult result = new BodaResult()
            {
                IsSuccess = true
            };

            try
            {
                byte subCmd = 0x01;  // 默认是位写入
                int typeLen = 1;
                if (typeof(T) != typeof(bool))
                {
                    subCmd = 0x00; // 字写入
                    typeLen = Marshal.SizeOf<T>() / 2;   // 当前类型下，每个数据需要多个地址的寄存器
                }

                #region 地址处理
                List<byte> startBytes = new List<byte>();
                if (area == McAddressArea.X || area == McAddressArea.Y)
                {
                    string str = startAddr.PadLeft(6, '0');
                    for (int i = 0; i < 6; i += 2)
                    {
                        string a = str[i].ToString() + str[i + 1].ToString();
                        startBytes.Add(Convert.ToByte(a, 16));
                    }
                    startBytes.Reverse();
                }
                else
                {
                    if (!int.TryParse(startAddr, out int addr))
                    {
                        throw new Exception("软元件地址不支持！");
                    }
                    startBytes.Add((byte)(addr % 256));
                    startBytes.Add((byte)(addr / 256 % 256));
                    startBytes.Add((byte)(addr / 256 / 256 % 256));
                }
                #endregion

                List<byte> bytes = new List<byte>
                {
                    0x50,0x00,
                    0x00,
                    0xFF,
                    0xFF,0x03,
                    0x00,

                    0x0C,0x00,  // 剩余字节长度
                    0x0A,0x00,

                    0x01,0x14,// 成批写入
                    subCmd,0x00,// 位操作
                };
                // 起始地址
                bytes.AddRange(startBytes);
                // 区域代码
                bytes.Add((byte)area);
                // 写入长度
                ushort len = (ushort)(typeLen * values.Count);
                // 这里指的是操作的点数，与字节无关
                bytes.AddRange(BitConverter.GetBytes(len));
                // 针对位操作时的处理
                if (subCmd == 0x01)
                {
                    //len = (ushort)Math.Ceiling(len * 1.0 / 2);    // 1个状态  1个字节 ；  2个状态   1个字节  ；  3个状态   2个字节    
                    // { 1 ,1 ,1 ,1 ,1,0}
                    // {}
                    for (int i = 0; i < values.Count; i++)
                    {
                        if (i % 2 == 0)
                        {
                            bytes.Add(0x00);
                        }
                        bool state = bool.Parse(values[i]?.ToString()
                                ?? throw new Exception($"位操作[{i}]中的值[{values[i]}]转换为String类型为空"));

                        if (state)
                        {
                            byte arg = 0x01;
                            if (i % 2 == 0)
                                arg *= 16;      // 按位或  0001 0000
                            bytes[bytes.Count - 1] |= arg;
                        }
                    }
                }
                else
                {
                    // 字节操作的时候
                    for (int i = 0; i < values.Count; i++)
                    {
                        dynamic item = values[i] ?? throw new Exception($"位操作[{i}]的values数组中的值为空");

                        bytes.AddRange(BitConverter.GetBytes(item));
                    }
                }
                ushort bytesLen = (ushort)(bytes.Count - 9);
                bytes[7] = BitConverter.GetBytes(bytesLen)[0];
                bytes[8] = BitConverter.GetBytes(bytesLen)[1];

                // 成批位处理的时候    处理方式，一个字节两个状态    每4个位一个状态
                // 拼接写入的数据部分

                // 发送并接收响应报文 
                BodaResult<byte> dataResult = _commUnit.SendAndReceive(bytes);
                if (!dataResult.IsSuccess)
                {
                    result.IsSuccess = false;
                    result.Message = dataResult.Message;
                }

                // 开始做异常判断 
                List<byte> stateBytes = dataResult.Datas.GetRange(9, 2);
                stateBytes.Reverse();
                string errorCode = string.Join("", stateBytes.Select(s => s.ToString("X2")));
                if (errorCode != "0000")
                {
                    if (Errors.ResponseError.ContainsKey(errorCode))
                    {
                        result.IsSuccess = false;
                        result.Message = Errors.ResponseError[errorCode];
                    }
                    else
                    {
                        result.IsSuccess = false;
                        result.Message = "未知异常";
                    }
                }

            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 随机写入，分为位操作和字操作
        /// </summary>
        /// <returns></returns>
        public BodaResult RandomWrite(List<McDataParameter> parameters, McSubCommands subCmd = McSubCommands.Word)
        {
            BodaResult result = new BodaResult();
            try
            {
                List<byte> bytes = new List<byte>
                {
                    0x50,0x00,
                    0x00,
                    0xFF,
                    0xFF,0x03,
                    0x00,

                    0x0C,0x00,  // 剩余字节长度
                    0x0A,0x00,

                    0x02,0x14,// 主命令
                    (byte)subCmd,0x00,// 子命令
                };

                if (subCmd == McSubCommands.Bit)
                {
                    // 拼接位的操作点数
                    bytes.Add(BitConverter.GetBytes(parameters.Count)[0]);

                    foreach (var param in parameters)
                    {
                        // 每个子项拼接三个信息：起始地址、区域代码、值
                        #region 地址转换
                        List<byte> startBytes = new List<byte>();
                        if (param.Area == McAddressArea.X || param.Area == McAddressArea.Y)
                        {
                            string str = param.Start.PadLeft(6, '0');
                            for (int i = 0; i < 6; i += 2)
                            {
                                string a = str[i].ToString() + str[i + 1].ToString();
                                startBytes.Add(Convert.ToByte(a, 16));
                            }
                            startBytes.Reverse();
                        }
                        else
                        {
                            if (!int.TryParse(param.Start, out int addr))
                            {
                                throw new Exception("软元件地址不支持！");
                            }
                            startBytes.Add((byte)(addr % 256));
                            startBytes.Add((byte)(addr / 256 % 256));
                            startBytes.Add((byte)(addr / 256 / 256 % 256));
                        }
                        #endregion
                        // 拼接起始地址
                        bytes.AddRange(startBytes);

                        // 拼接区域代码
                        bytes.Add((byte)param.Area);

                        // 拼接当前地址需要写入的结果
                        if (bool.Parse(param.Datas[0]?.ToString() ?? throw new Exception($"值[{param.Datas[0]}]转换为String类型为空")))
                        {
                            bytes.Add(0x01);
                        }
                        else
                            bytes.Add(0x00);
                    }
                }
                else
                {
                    // 接字点数
                    // 接双字点数
                    bytes.Add(BitConverter.GetBytes(parameters.Count(p => !p.IsSecond))[0]);// 字操作点数
                    bytes.Add(BitConverter.GetBytes(parameters.Count(p => p.IsSecond))[0]);// 双字操作点数

                    // 需要一个排序，目的就是把字放在前，双字放后面
                    List<McDataParameter> sortList = parameters.OrderBy(p => p.IsSecond).ToList();
                    foreach (var param in sortList)
                    {
                        #region 地址转换
                        List<byte> startBytes = new List<byte>();
                        if (param.Area == McAddressArea.X || param.Area == McAddressArea.Y)
                        {
                            string str = param.Start.PadLeft(6, '0');
                            for (int i = 0; i < 6; i += 2)
                            {
                                string a = str[i].ToString() + str[i + 1].ToString();
                                startBytes.Add(Convert.ToByte(a, 16));
                            }
                            startBytes.Reverse();
                        }
                        else
                        {
                            if (!int.TryParse(param.Start, out int addr))
                            {
                                throw new Exception("软元件地址不支持！");
                            }
                            startBytes.Add((byte)(addr % 256));
                            startBytes.Add((byte)(addr / 256 % 256));
                            startBytes.Add((byte)(addr / 256 / 256 % 256));
                        }
                        #endregion
                        // 拼接起始地址
                        bytes.AddRange(startBytes);

                        // 拼接区域代码
                        bytes.Add((byte)param.Area);

                        dynamic v = param.Datas[0];
                        byte[] vBytes = BitConverter.GetBytes(v);
                        // 
                        bytes.Add(vBytes[0]);
                        bytes.Add(vBytes[1]);

                        if (param.IsSecond)
                        {
                            bytes.Add(vBytes[2]);
                            bytes.Add(vBytes[3]);
                        }
                    }
                }
                // 计算报文长度
                ushort bytesLen = (ushort)(bytes.Count - 9);
                bytes[7] = BitConverter.GetBytes(bytesLen)[0];
                bytes[8] = BitConverter.GetBytes(bytesLen)[1];

                // 发送并接收响应报文 
                BodaResult<byte> dataResult = _commUnit.SendAndReceive(bytes);
                if (!dataResult.IsSuccess)
                {
                    result.IsSuccess = false;
                    result.Message = dataResult.Message;
                }

                // 开始做异常判断 
                List<byte> stateBytes = dataResult.Datas.GetRange(9, 2);
                stateBytes.Reverse();
                string errorCode = string.Join("", stateBytes.Select(s => s.ToString("X2")));
                if (errorCode != "0000")
                {
                    if (Errors.ResponseError.ContainsKey(errorCode))
                    {
                        result.IsSuccess = false;
                        result.Message = Errors.ResponseError[errorCode];
                    }
                    else
                    {
                        result.IsSuccess = false;
                        result.Message = "未知异常";
                    }
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }
            return result;
        }

        /// <summary>
        /// 多块成批写入，区分字和位存储区
        /// </summary>
        /// <returns></returns>
        public BodaResult MultiWrite(List<McDataParameter> parameters)
        {
            BodaResult result = new BodaResult();
            try
            {
                List<byte> bytes = new List<byte>
                {
                    0x50,0x00,
                    0x00,
                    0xFF,
                    0xFF,0x03,
                    0x00,

                    0x0C,0x00,  // 剩余字节长度
                    0x0A,0x00,

                    0x06,0x14,// 成批写入
                    0x00,0x00,// 子命令
                };

                bytes.Add(BitConverter.GetBytes(parameters.Count(p => !p.IsSecond))[0]);// 字操作块数
                bytes.Add(BitConverter.GetBytes(parameters.Count(p => p.IsSecond))[0]);// 位操作块数
                // 需要排序，将位操作块放到后面
                List<McDataParameter> sortList = parameters.OrderBy(p => p.IsSecond).ToList();
                foreach (var param in sortList)
                {
                    #region 地址转换
                    List<byte> startBytes = new List<byte>();
                    if (param.Area == McAddressArea.X || param.Area == McAddressArea.Y)
                    {
                        string str = param.Start.PadLeft(6, '0');
                        for (int i = 0; i < 6; i += 2)
                        {
                            string a = str[i].ToString() + str[i + 1].ToString();
                            startBytes.Add(Convert.ToByte(a, 16));
                        }
                        startBytes.Reverse();
                    }
                    else
                    {
                        if (!int.TryParse(param.Start, out int addr))
                        {
                            throw new Exception("软元件地址不支持！");
                        }
                        startBytes.Add((byte)(addr % 256));
                        startBytes.Add((byte)(addr / 256 % 256));
                        startBytes.Add((byte)(addr / 256 / 256 % 256));
                    }
                    #endregion
                    // 拼接起始地址
                    bytes.AddRange(startBytes);

                    // 拼接区域代码
                    bytes.Add((byte)param.Area);

                    // 当前块写入几个值
                    bytes.Add(BitConverter.GetBytes(param.Datas.Count)[0]);
                    // 不管字存储还是位存储，数据部分都是以两个字节处理   一个字
                    foreach (dynamic v in param.Datas)
                    {
                        bytes.Add(BitConverter.GetBytes(v)[0]);
                        bytes.Add(BitConverter.GetBytes(v)[1]);
                    }
                }


                // 计算报文长度
                ushort bytesLen = (ushort)(bytes.Count - 9);
                bytes[7] = BitConverter.GetBytes(bytesLen)[0];
                bytes[8] = BitConverter.GetBytes(bytesLen)[1];

                // 发送并接收响应报文 
                BodaResult<byte> dataResult = _commUnit.SendAndReceive(bytes);
                if (!dataResult.IsSuccess)
                {
                    result.IsSuccess = false;
                    result.Message = dataResult.Message;
                }

                // 开始做异常判断 
                List<byte> stateBytes = dataResult.Datas.GetRange(9, 2);
                stateBytes.Reverse();
                string errorCode = string.Join("", stateBytes.Select(s => s.ToString("X2")));
                if (errorCode != "0000")
                {
                    if (Errors.ResponseError.ContainsKey(errorCode))
                    {
                        result.IsSuccess = false;
                        result.Message = Errors.ResponseError[errorCode];
                    }
                    else
                    {
                        result.IsSuccess = false;
                        result.Message = "未知异常";
                    }
                }
            }
            catch (Exception ex)
            {
                result.IsSuccess = false;
                result.Message = ex.Message;
            }
            return result;
        }

        public BodaResult SendMsgc(byte[] bytes, int timeout = 1500)
        {
            throw new NotImplementedException();
        }

        public BodaResult<byte> ReceiveMsg(int timeout = 2000, int bytesLen = 1024)
        {
            throw new NotImplementedException();
        }
        #endregion
    }
}